﻿package nieflash.effect {
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Matrix;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.geom.Point;
	import flash.geom.ColorTransform;
	import flash.filters.GlowFilter;
	import flash.filters.BevelFilter;
	import flash.filters.ColorMatrixFilter;
	import flash.display.BlendMode;
	
	public class cloud extends Sprite {
		private var _image:BitmapData;
		
		public function cloud(width:int, height:int, seed:int, contrast:Number = 1, color:uint = 0xFFFFFF, light:uint = 0xFFFFFF, shadow:uint = 0xDDDDDD):void {
			var _cloud:Bitmap;
			var gradiation:Sprite = new Sprite();
			var drawMatrix:Matrix = new Matrix();
			drawMatrix.createGradientBox(width, height);
			gradiation.graphics.beginGradientFill("radial", [0x000000, 0x000000], [0, 1], [0, 255], drawMatrix);
			gradiation.graphics.drawRect(0, 0, width, height);
			gradiation.graphics.endFill();
			var alphaBmp:BitmapData = new BitmapData(width, height);
			alphaBmp.perlinNoise(width / 3, height / 2.5, 5, seed, false, true, 1 | 2 | 4, true);
			var zoom:Number = 1 + (contrast - 0.1) / (contrast + 0.9);
			if (contrast < 0.1) {
				zoom = 1;
			}
			if (contrast > 2.0) {
				zoom = 2;
			}
			var ctMatrix:Array = [contrast + 1, 0, 0, 0, -128 * contrast, 0, contrast + 1, 0, 0, -128 * contrast, 0, 0, contrast + 1, 0, -128 * contrast, 0, 0, 0, 1, 0];
			alphaBmp.draw(gradiation, new Matrix(zoom, 0, 0, zoom, -(zoom - 1) / 2 * width, -(zoom - 1) / 2 * height));
			alphaBmp.applyFilter(alphaBmp, alphaBmp.rect, new Point(), new ColorMatrixFilter(ctMatrix));
			_image = new BitmapData(width, height, true, 0xFF << 24 | color);
			_image.copyChannel(alphaBmp, alphaBmp.rect, new Point(), 4, 8);
			_image.applyFilter(_image, _image.rect, new Point(), new GlowFilter(light, 1, 4, 4, 1, 3, true));
			var bevelSize:Number=Math.min(width,height)/30;
			_image.applyFilter(_image, _image.rect, new Point(), new BevelFilter(bevelSize, 45, light, 1, shadow, 1, bevelSize / 5, bevelSize / 5, 1, 3));
			var image2:BitmapData = new BitmapData(width, height, true, 0);
			image2.draw(createGradientRect(width, height, [light, color, shadow], [1, 0.5, 1], null, 90), null, null, BlendMode.MULTIPLY);
			image2.copyChannel(alphaBmp, alphaBmp.rect, new Point(), 4, 8);
			_image.draw(image2, null, null, BlendMode.MULTIPLY);
			alphaBmp.dispose();
			_cloud = new Bitmap(_image);
			addChild(_cloud);
			this.dispatchEvent(new Event(Event.COMPLETE));
		}
		
		public function get bitmapData():BitmapData {
			return _image;
		}

		private function createGradientRect(width:Number, height:Number, colors:Array, alphas:Array, ratios:Array = null, rotation:Number = 0):Sprite {
			var i:int, rts:Array = new Array();
			if (ratios == null) {
				for (i = 0; i < colors.length; i++) {
					rts.push(int(255 * i / (colors.length - 1)));
				}
			} else {
				for (i = 0; i < ratios.length; i++) {
					rts[i] = Math.round(ratios[i] * 255);
				}
			}
			var sp:Sprite = new Sprite();
			var mtx:Matrix = new Matrix();
			mtx.createGradientBox(width, height, Math.PI / 180 * rotation, 0, 0);
			if (colors.length == 1 && alphas.length == 1) {
				sp.graphics.beginFill(colors[0], alphas[0]);
			} else {
				sp.graphics.beginGradientFill("linear", colors, alphas, rts, mtx);
			}
			sp.graphics.drawRect(0, 0, width, height);
			sp.graphics.endFill();
			return sp;
		}
	}
}